package com.qumitech.visualnovel.controller.hook.filter.param;

import java.io.*;
import java.util.*;

import org.springframework.web.util.WebUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.annotation.WebFilter;

import org.springframework.core.Ordered;

import lombok.extern.slf4j.Slf4j;
import com.qumitech.visualnovel.component.util.IpUtil;

@Slf4j
@WebFilter(filterName = "paramFilter", urlPatterns = "/*")
public class ParamsFilter extends OncePerRequestFilter implements Ordered {
    // put filter at the end of all other filters to make sure we are processing after all others
    private int order = Ordered.LOWEST_PRECEDENCE - 8;

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);

        long time = System.currentTimeMillis();
        String requestId = UUID.randomUUID().toString();
        String method = wrapperRequest.getMethod();
        String token = wrapperRequest.getHeader("token");
        String cookie = wrapperRequest.getHeader("Cookie");
        String ip = IpUtil.getIpAddr(wrapperRequest);
        String url = getQueryUrl(wrapperRequest);
        String requestBody = getRequestBody(wrapperRequest);
        log.info("[request] <{}>, ip:<{}>, url:<{}>, body:<{}>, token:<{}>, requestId:<{}>,Cookie:<{}>",
                method, ip, url, requestBody, token, requestId, cookie);

        filterChain.doFilter(wrapperRequest, wrapperResponse);
        String responseBody = getResponseBody(wrapperResponse);
        wrapperResponse.copyBodyToResponse();

        long cost = System.currentTimeMillis() - time;
        log.info("[response] <{}> requestId:<{}>, costTime:<{}>, status:<{}>, content:{}", method, requestId, cost, wrapperResponse.getStatus(), responseBody);
    }

    private String getQueryUrl(HttpServletRequest servletRequest) {
        return servletRequest.getRequestURL() +
                (servletRequest.getQueryString() == null ? "" : ("?" + servletRequest.getQueryString()));
    }

    private String getRequestBody(ContentCachingRequestWrapper request) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper == null) return "";

        byte[] buf = wrapper.getContentAsByteArray();
        if (buf == null || buf.length <= 0) return "";

        try {
            String body = new String(buf, 0, buf.length, wrapper.getCharacterEncoding()).replaceAll("\\n", "");
            return body;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    private String getResponseBody(ContentCachingResponseWrapper response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper == null) return "";

        byte[] buf = wrapper.getContentAsByteArray();
        if (buf == null || buf.length <= 0) return "";

        try {
            String body = new String(buf, 0, buf.length, "utf8");
            return body;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
